﻿using Itech_Run.Domain.Shared.Const;
using Itech_Run.HttpApi.Shared.Result;
using Itech_Run.Helper.Attribute;
using Itech_Run.HttpApi.Shared.Options;
using Itech_Run.Sys.Application.Contracts.Service;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Options;
using System.Text.Json;
using Volo.Abp.Caching;

namespace Itech_Run.Sys.HttpApi.Middleware
{
    public class ModuleAuthMiddleware : BaseMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly IDistributedCache<List<string?>, string> _moduleCache;
        private readonly ISysModuleService _sysModuleService;
        private readonly IOptions<CacheOptions>? _cacheOptions;
        private Func<string, string, string, object[]?> _moduleAttributeDelegate;

        private readonly IDistributedCache<string, string> _testCache;
        public ModuleAuthMiddleware(RequestDelegate next, IApplicationBuilder app, Func<string, string, string, object[]?> moduleAttributeDelegate, ISysModuleService sysModuleService) : base(app)
        {
            _next = next;
            _moduleCache = (IDistributedCache<List<string?>, string>)app.ApplicationServices.GetService(typeof(IDistributedCache<List<string?>, string>));
            _sysModuleService = sysModuleService;
            _cacheOptions = (IOptions<CacheOptions>?)app.ApplicationServices.GetService(typeof(IOptions<CacheOptions>));
            _moduleAttributeDelegate = moduleAttributeDelegate;

            _testCache = (IDistributedCache<string, string>)app.ApplicationServices.GetService(typeof(IDistributedCache<string, string>));
        }

        public async Task Invoke(HttpContext context)
        {
            if (context.User.Identity != null && context.User.Identity.Name != null)
            {
                var operateUser = context.User.Identity.Name;
                //从Sys_Module中获取，有效的&ApiController不为空的 ，去重复的ApiController集合
                var allApiControllers = await _moduleCache.GetOrAddAsync(CacheConst.Module_ApiController_All,
                    () => _sysModuleService.GetSysModuleApiController(),
                    () =>
                    {
                        return new DistributedCacheEntryOptions
                        {
                            AbsoluteExpiration = DateTime.Now.AddSeconds(_cacheOptions?.Value.ModuleAuthAllTime ?? 0)
                        };
                    });

                //获取当前User》Role》Sys_Module的，有效的&ApiController不为空的 ，去重复的ApiController集合
                var myApiControllers = await _moduleCache.GetOrAddAsync(string.Concat("UserRole", "_", operateUser),
                   () => _sysModuleService.GetSysModuleApiControllerByUserRole(operateUser ?? ""),
                   () =>
                   {
                       return new DistributedCacheEntryOptions
                       {
                           AbsoluteExpiration = DateTime.Now.AddSeconds(_cacheOptions?.Value.ModuleAuthUserTime ?? 0)
                       };
                   });

                var isAuth = await CurrentControllerIsAuth(allApiControllers, myApiControllers, context);
                if (!isAuth)
                {
                    context.Response.ContentType = "application/json; charset=utf-8 ";
                    var stream = context.Response.Body;
                    await JsonSerializer.SerializeAsync(stream, new CustomResult { Code = CustomResultCode.无操作权限.To<int>().ToString(), Message = "无此模块权限" }
                    , new JsonSerializerOptions
                    {
                        PropertyNamingPolicy = JsonNamingPolicy.CamelCase
                    });
                    return;
                }
            }

            await _next(context);
        }

        private async Task<bool> CurrentControllerIsAuth(List<string> allApiControllers, List<string> myApiControllers, HttpContext context)
        {
            allApiControllers = allApiControllers.Select(s => s.ToLower()).ToList();
            myApiControllers = myApiControllers.Select(s => s.ToLower()).ToList();

            var path = context.Request.Path.Value;
            var splitArr = path?.Split('/', StringSplitOptions.RemoveEmptyEntries);
            if (splitArr?.Length >= 2)
            {
                var controller = splitArr[splitArr.Length - 2].ToLower();
                //若当前controller在大集合allApiControllers里则参与权限判断，否则放行
                if (allApiControllers.Contains(controller))
                {
                    #region 对添加了ModuleOpenAttribute特性的Action放行
                    var actualController = GetActualControllerName(controller);
                    var action = splitArr[splitArr.Length - 1];
                    var assemblyName = await GetAssemblyName(_sysModuleService, actualController);
                    var customAttributes = _moduleAttributeDelegate(assemblyName ?? "", actualController + "Controller", action);
                    if (customAttributes is not null)
                        for (int i = 0; i < customAttributes.Length; i++)
                        {
                            var item = customAttributes[i];
                            if (item is ModuleOpenAttribute)
                            {
                                return true;
                            }
                        }
                    #endregion

                    //如果不在当前用户集合里，则没有权限
                    if (!myApiControllers.Contains(controller))
                        return false;
                }
            }
            return true;
        }
    }
}
